﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NhWeather.Modbus
{
    /// <summary>
    /// 发送命令类
    /// </summary>
    public abstract class SentCmd : BaseFrame
    {
        protected SentCmd(byte address, byte code)
        {
            Address = address;
            Code = code;
        }

        /// <summary>
        /// 是否自动发送，程序开始是即发送
        /// </summary>
        public bool Automatic { get; set; }

        /// <summary>
        /// 是否继续发送指令，实时、历史
        /// </summary>
        public bool Continue { get; set; }

        /// <summary>
        /// 继续发送下一条指令延时，实时为1s，历史为0，同步完成为60s
        /// </summary>
        public uint DelayTime { get; set; }

        /// <summary>
        /// 是否重置参数，历史、采集仪配置
        /// </summary>
        public bool Reset { get; set; }

        /// <summary>
        /// 是否是响应的数据，效验通过，功能码、地址符合
        /// </summary>
        /// <param name = "byts" >数据帧</ param >
        /// < returns ></ returns >
        public virtual bool IsAnswer(byte[] byts)
        {
            bool result = false;
            var mb = new FrameValid(byts);
            if (mb.IsValid && mb.Code == (int)Code && mb.Address == Address)
            {
                result = true;
            }
            return result;
        }

        /// <summary>
        /// 获取命令
        /// </summary>
        /// <returns></returns>
        public abstract byte[] GetCmd();

        /// <summary>
        /// 切换到下一条命令，Continue命令有的功能
        /// </summary>
        public virtual void NextCmd() { }

        /// <summary>
        /// 重置命令
        /// </summary>
        public virtual void ResetCmd() { }
    }

    public class RealTimeCmdHelper : SentCmd
    {
        public RealTimeCmdHelper(byte address) : base(address, 0x04)
        {
            Automatic = true;
            DelayTime = 1000;
        }

        /// <summary>
        /// 读取多少寄存器，高8位无意义
        /// </summary>
        public byte Len { get; set; } = 27;

        /// <summary>
        /// 读取起始寄存器地址，默认为0
        /// </summary>
        public ushort Index { get; set; }

        /// <summary>
        /// 组帧，读实时数据命令
        /// </summary>
        /// <returns></returns>
        public override byte[] GetCmd()
        {
            byte[] cmd = new byte[8] { Address, Code, (byte)(Index >> 8), (byte)Index, 0, Len, 0, 0 };
            AddCrc(ref cmd);
            return cmd;
        }
    }

    /// <summary>
    /// 读历史数据命令帮助类
    /// </summary>
    public class HistoryCmdHelper : SentCmd
    {
        /// <summary>
        /// 历史数据偏移量
        /// </summary>
        protected UInt32 OffSet { get; set; }

        public HistoryCmdHelper(byte address) : base(address, 0x41)
        {
            Automatic = true;
        }

        /// <summary>
        /// 构造函数，校时类构造时调用
        /// </summary>
        /// <param name="address"></param>
        /// <param name="code"></param>
        public HistoryCmdHelper(byte address, byte code) : base(address, code) { }

        /// <summary>
        /// 切换到下一条命令
        /// </summary>
        public override void NextCmd() { OffSet += 1; }

        /// <summary>
        /// 重置命令,从最近读历史数据
        /// </summary>
        public override void ResetCmd() { OffSet = 0; }

        /// <summary>
        /// 组帧，读历史数据命令
        /// </summary>
        /// <returns></returns>
        public override byte[] GetCmd()
        {
            byte[] cmd = new byte[8] { Address, Code, (byte)(OffSet >> 24), (byte)(OffSet >> 16),
                (byte)(OffSet >> 8), (byte)OffSet, 0, 0 };
            AddCrc(ref cmd);
            return cmd;
        }
    }

    /// <summary>
    /// 读配置数据命令帮助类
    /// </summary>
    public class ConfigCmdHelper : HistoryCmdHelper
    {
        public ConfigCmdHelper(byte address) : base(address, 0x11)
        {
            Code = 0x11;
        }

        public override void NextCmd() { OffSet += 0x10; }

        /// <summary>
        ///  组帧，读配置数据命令
        /// </summary>
        /// <returns></returns>
        public override byte[] GetCmd()
        {
            byte[] cmd = new byte[8] {Address,Code, (byte)((OffSet >> 8) + 0x10), (byte)OffSet,
            0,0x10,0,0};
            AddCrc(ref cmd);
            return cmd;
        }
    }

    /// <summary>
    /// 校时命令
    /// </summary>
    public class CalibrationTimeCmdHelper : SentCmd
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="address"></param>
        public CalibrationTimeCmdHelper(byte address) : base(address, 0x10)
        {
        }

        /// <summary>
        /// 组帧，校正时间
        /// </summary>
        /// <returns></returns>
        public override byte[] GetCmd()
        {
            DateTime dt = DateTime.Now;
            byte[] cmd = new byte[15] {Address,Code,0,0,0,3,6,(byte)(dt.Year - 2000), (byte)dt.Month,
           (byte)dt.Day, (byte)dt.Hour,(byte)dt.Minute,(byte)dt.Second,0,0};
            AddCrc(ref cmd);
            return cmd;
        }
    }

}
